package com.wf.chatManagement.service.local.impl;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Description: WebSocket连接
 */
@Service
@ServerEndpoint(value = "/websocket/{userId}")
@Slf4j
public class WebSocketService {

    /**
     * 推送消息业务类
     */
    private static PushMessageService pushMessageService;

    /**
     * 注入推送消息业务类
     *
     * @param pushMessageService 推送消息业务类
     */
    @Autowired
    public void injectionPushMessageService(PushMessageService pushMessageService) {
        WebSocketService.pushMessageService = pushMessageService;
    }

    /**
     * 存放每个客户端对应的WebSocket对象。实现服务端与单一客户端通信的话，其中Key可以为用户标识
     */
    private static ConcurrentHashMap<String, WebSocketService> webSocketSet = new ConcurrentHashMap<String, WebSocketService>();

    /**
     * 与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    private Session session;

    /**
     * 当前发消息的人员编号
     */
    private String userId = "";


    /**
     * 连接建立成功调用的方法
     *
     * @param userId           发送者ID，是由谁发送的
     * @param webSocketSession 可选的参数。session为与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    @OnOpen
    public void onOpen(@PathParam(value = "userId") String userId, Session webSocketSession) {
        if (StrUtil.isNotBlank(userId)) {
            this.session = webSocketSession;
            this.userId = userId;
            //存储当前在线用户
            pushMessageService.newOnlineUsers(userId);
            //加入map中，绑定当前用户和socket
            webSocketSet.put(userId, this);
            log.info("用户：{} 建立连接", userId);
            //推送缓存的离线消息
            pushMessageService.sendCachedOfflineMessages(userId);
        }
    }


    /**
     * 连接关闭调用的方法
     *
     * @param userId 当前关闭连接的用户Id
     */
    @OnClose
    public void onClose(@PathParam(value = "userId") String userId) {
        if (webSocketSet.containsKey(userId)) {
            webSocketSet.remove(userId);
            //移除当前用户在线状态
            pushMessageService.reduceOnlineUsers(userId);
            log.info("用户：{} 关闭连接", userId);
        }
    }


    /**
     * 收到客户端消息后调用的方法
     *
     * @param content 客户端发送过来的消息
     * @param session 可选的参数
     */
    @OnMessage
    public void onMessage(String content, Session session) {
        if (StrUtil.isNotBlank(content)) {
            //发送消息
            if (!pushMessageService.sendChatMessage(content,false,false)){
                log.info("聊天消息，{} 发送失败", content);
            }
        }

    }

    /**
     * 发生错误时调用
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();

        log.info("webSocket错误；{}", error.getMessage());
    }

    /**
     * 向指定用户发送消息
     *
     * @param message
     */
    public boolean sendAssignmentMessage(String userId, String message, int megType) {
        boolean result = false;
        //判断当前用户是否在线
        if (webSocketSet.containsKey(userId)) {
            result = webSocketSet.get(userId).sendMessage(message);
        } else {
            //判断是否为聊天消息
            if (megType == PushMessageService.MESSAGE_TYPE_CHAT) {
                result = pushMessageService.setOfflineUserChat(userId, message);
            //判断是否为留言消息
            } else if (megType ==  PushMessageService.MESSAGE_TYPE_LEAVING_A_MESSAGE) {
                result = pushMessageService.setOfflineUserMessage(userId, message);
            }
        }
        return result;
    }


    /**
     * 服务器主动向客户端推送消息
     *
     * @param message 需要推送的消息
     */
    public boolean sendMessage(String message) {
        try {
            this.session.getBasicRemote().sendText(message);
            return true;
        } catch (IOException e) {
            log.info("发送消息{}失败，错误为{}", message, e.getMessage());
        }
        return false;
    }


    /**
     * 给所有人发消息
     *
     * @param message 需要发送的消息
     */
    public boolean sendAll(String message) {
        try {
            //遍历HashMap
            for (String key : webSocketSet.keySet()) {
                //判断接收用户是否是当前发消息的用户
                if (!userId.equals(key)) {
                    webSocketSet.get(key).sendMessage(message);
                }
            }
            return true;
        } catch (Exception e) {
            log.info("给所有用户发消息时，出现错误：{}", e.getMessage());
        }
        return false;
    }


}
